package com.apestech.framework.sql.variable;

import java.util.ArrayList;
import java.util.Date;

import com.apestech.framework.json.JSONObject;
import com.apestech.framework.sql.MultiDataBase;
import com.apestech.framework.util.DateUtil;
import com.apestech.framework.util.StringUtil;

/**
 * SQL变量单值解析
 * @author hupo
 *
 */
public class SqlSingleValue extends StringUtil{
	
	private Object value;
	private String key;
	private String valueClass;
	private String varType;
	private Object resultValue;
	private String resultType;
	private String resultPrintValue;
	private String fieldType;
	private String fieldValue;
	private boolean fieldNull;
	private String tabName;
	private String dbType;
	private String sqlType;

	public SqlSingleValue(String dbType, String sqlType){
		this.dbType=dbType;
		this.sqlType=sqlType;
	}

	public String getDbType() {
		return dbType;
	}

	public String getResultPrintValue(){
		return this.resultPrintValue;
	}
	
	public String getResultType(){
		return this.resultType;
	}
	
	public Object getResultValue(){
		return this.resultValue;
	}

	public String getVarType() {
		return varType;
	}

	public void setVar(String tabName, String key, Object value, String fieldType, String fieldValue, String notNull){
		this.tabName=tabName;
		if(value instanceof JSONObject){
			this.value=((JSONObject) value).get("value");
		} else {
			this.value=value;
		}
		if(this.value instanceof ArrayList){
			if(((ArrayList)this.value).size()==1){
				this.value=((ArrayList)this.value).get(0);
			}
		}
		this.key=key;
		this.fieldType=fieldType;
		this.fieldValue=fieldValue;
		this.fieldNull=!"1".equals(notNull);
		if(this.value!=null){
			this.valueClass=this.value.getClass().getName();
			switch(this.valueClass){
				case "java.lang.String":
					this.varType="VARCHAR2";
					break;
				case "java.util.Date":
					this.varType="DATE";
					break;
				case "java.sql.Date":
					this.varType="DATE";
					break;
				case "java.lang.Integer":
					this.varType="NUMBER";
					break;
				case "java.lang.Long":
					if(this.fieldType.equals("DATE")){
						this.varType="DATE";
					} else {
						this.varType="NUMBER";
					}
					break;
				case "java.lang.Double":
					this.varType="NUMBER";
					break;
				case "java.sql.Timestamp":
					this.varType="DATE";
					break;
				case "java.math.BigDecimal":
					this.varType="NUMBER";
					break;
			}
		}
		if("DATE".equals(this.varType) && this.fieldType==null){
			this.fieldValue="DATE";
		}
	}
	
	//数据字典获取字段信息可放在外部调用，这里通过入参方式传入
	public void expain() throws Exception{
		if(this.value==null && !"".equals(fieldValue)){
			this.value=fieldValue;
		}
		setNull(this.value);
 		if(this.value!=null){
			setKeyWord();
			if(this.resultValue==null){
				String type=this.fieldType;
				if(type==null){
					type=this.varType;
				}
				if(type==null){
					String sname=value.getClass().getName();
					if(sname.indexOf("ArrayList")>=0){
						resultValue=value;
						resultType="ArrayList";
						return;
					}
				}
				type=type.toUpperCase();
				if(type.indexOf("CLOB")>=0){
					type="CLOB";
				}
				switch(type){
					case "VARCHAR2":
						setCHAR(this.value);
						break;
					case "DATE":
						setDate(this.value);
						break;
					case "TIMESTAMP(6)":
						setDate(this.value);
						break;
					case "CLOB":
						setCLOB(this.value);
						break;
					case "NUMBER":
						setNum(this.value);
						break;
				}
			}
		}
		if("-1".equals(this.resultValue)){
			this.resultValue=null;
		}
	}
	
	private void setCHAR(Object val){
		this.resultValue=castToString(val);
		if("SYSDATE".equals(this.resultValue)) this.resultPrintValue= (String) this.resultValue;
		else this.resultPrintValue="'"+this.resultValue+"'";
		this.resultType="VARCHAR2";
	}

	private void setCLOB(Object val){
		this.resultValue=castToString(val);
		this.resultPrintValue="'"+this.resultValue+"'";
		this.resultType="CLOB";
	}
	
	private void setNum(Object val){
		if("false".equals(val) || val.equals(false)){
			val=0;
		} else if("true".equals(val) || val.equals(true)){
			val=1;
		}
		this.resultValue=castToBigDecimal(val);
		this.resultType="BIG";
		this.resultPrintValue=castToString(val);
	}
	
	private void setDate(Object val) throws Exception{
		MultiDataBase db=new MultiDataBase(this.dbType);
		if ("SYSDATE".equals(val)){
			this.resultValue=db.getSysDateTime();
			this.resultPrintValue= (String) this.resultValue;
		}else if(val instanceof String){
			this.resultValue=DateUtil.strToDate((String) val);
			this.resultPrintValue=db.getDateTime((Date)this.resultValue);
		}else if(val instanceof Long){
			this.resultValue=new Date((Long) val);
			this.resultPrintValue=db.getDateTime((Date)this.resultValue);
		} else {
			this.resultValue=val;
			this.resultPrintValue=db.getDateTime((Date)val);
		}
		this.resultType="DATE";
	}
	
	private void setNull(Object val) throws Exception{
		this.resultPrintValue=null;
		this.resultType=null;
		this.resultValue="-1";
		if(val==null){
			if(!"SELECT".equals(this.sqlType) && !this.fieldNull){
				//throw new Exception(getMessage("SqlVar_NotNull"," 以下错误信息，请提交给研发人员:\n 【 ({0}) 】表中 【 ({1}) 】字段，不允许为空!",this.tabName, this.key));
			}
		}
		if("SELECT".equals(this.sqlType)){
			throw new Exception(getMessage("SqlVar_NotNull"," 以下错误信息，请提交给研发人员:\n 【 ({0}) 】查询条件值不允许为空!", this.key));
		}
	}
	
	private void setKeyWord() throws Exception{
		MultiDataBase db=new MultiDataBase(this.dbType);
		this.resultType=null;
		this.resultValue=null;
		if("VARCHAR2".equals(this.varType)){
			if(this.value.equals(true)) this.value="1";
			else if(this.value.equals(false)) this.value="0";
			switch(castToString(this.value)){
				case "DEFAULT_VALUE":
					if(this.fieldValue==null) setNull(this.fieldValue);
					else {
						switch(this.fieldType){
							case "VARCHAR2":
								setCHAR(this.fieldValue);
								break;
							case "DATE":
								setDate(this.fieldValue);
								break;
							case "NUMBER":
								setNum(this.fieldValue);
								break;
						}
					}
					break;
				case "SYS_DATE":
					this.resultPrintValue=db.getDate(db.getSysDateTime());
					break;
				case "SYS_DATETIME":
					this.resultPrintValue=db.getSysDateTime();
					break;
				case "SYS_TIMESTAMP":
					this.resultPrintValue=db.getTimeStamp();
					break;
				case "SYS_VERSION":
					this.resultPrintValue="NVL("+this.key+",0)+1";
					break;
			}
		}
		if(this.resultValue==null){
			this.resultValue=this.resultPrintValue;
		}
	}
	
	
}
